package jnzb.ui;

import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.text.DecimalFormat;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import jnzb.JNZB;
import jnzb.control.Controller;

/**
 * This is the top level class for the GUI
 * 
 * @author AA1
 * 
 */
@SuppressWarnings("serial")
public class UserInterface extends JFrame {

	private JPanel mainPanel;
	private NZBPanel nzbPanel;
	private InfoPanel infoPanel;
	private CurrentPanel currentPanel;
	private ControlPanel controlPanel;
	private QueuePanel queuePanel;

	private DecimalFormat percentFormat = new DecimalFormat("#0.00");

	/**
	 * Construct the gui and sub-components and register action events against
	 * the controller
	 * 
	 * @param controller
	 *            - the controller that will handle events
	 */
	public UserInterface(final Controller controller) {
		setLookAndFeel();
		create();
		registerListeners(controller);
	}

	/**
	 * Register the listeners for the GUI events. Handles it own then drills
	 * down sub components.
	 * 
	 * @param controller
	 */
	private void registerListeners(final Controller controller) {
		this.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent event) {
				controlPanel.doExit(controller);
			}
		});

		this.controlPanel.registerListeners(controller);
		this.queuePanel.registerListeners(controller);
	}

	/**
	 * Create and assemble the gui.
	 */
	private void create() {
		// We will tidy up ourselves
		this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

		resetTitle();
		this.setResizable(true);

		// Create the panel with the search and results displays on
		this.add(createMainPanel());

		// Locate components relative to each other
		this.pack();
		// Centre on the screen - important this is done after the pack()
		this.setLocationRelativeTo(null);

		// Redo the main frame size to twice the packed width
		Dimension d = this.getPreferredSize();
		d.setSize(d.getWidth() * 2, d.getHeight());
		this.setPreferredSize(d);

		// Now pack again
		this.pack();

		// Show it
		this.setVisible(true);
	}

	/**
	 * @return
	 */
	private JPanel createMainPanel() {
		this.mainPanel = new JPanel();
		this.mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));

		// Add some padding as an empty border
		this.mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10));

		this.queuePanel = new QueuePanel();
		this.mainPanel.add(this.queuePanel);

		// Add the NZB info panel
		this.nzbPanel = new NZBPanel();
		this.mainPanel.add(this.nzbPanel);

		// Add the Current download info panel
		this.currentPanel = new CurrentPanel();
		this.mainPanel.add(this.currentPanel);

		// Add the info panel
		this.infoPanel = new InfoPanel();
		this.mainPanel.add(this.infoPanel);

		// Add the button panel
		this.controlPanel = new ControlPanel(this);
		this.mainPanel.add(this.controlPanel);

		return this.mainPanel;
	}

	/**
	 * Display a general error message in a modal error dialog, relative to the
	 * entire screen. Will create a runnable and pass to event thread
	 * 
	 * @param message
	 *            - the message to display
	 * @param title
	 *            - the title to set of the dialog
	 */
	public static void showError(final String message, final String title) {
		Runnable shError = new Runnable() {
			public void run() {

				JOptionPane.showMessageDialog(null, message,
						title == null ? "Error" : title,
						JOptionPane.ERROR_MESSAGE);
			}
		};
		SwingUtilities.invokeLater(shError);
	}

	/**
	 * Set the look and feel to that of the native system
	 */
	public static void setLookAndFeel() {
		// Install the native look and feel
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (InstantiationException e) {
			throw new RuntimeException(e.getMessage(), e);
		} catch (ClassNotFoundException e) {
			throw new RuntimeException(e.getMessage(), e);
		} catch (UnsupportedLookAndFeelException e) {
			throw new RuntimeException(e.getMessage(), e);
		} catch (IllegalAccessException e) {
			throw new RuntimeException(e.getMessage(), e);
		}
	}

	public NZBPanel getNzbPanel() {
		return nzbPanel;
	}

	public CurrentPanel getCurrentPanel() {
		return currentPanel;
	}

	public InfoPanel getInfoPanel() {
		return infoPanel;
	}

	public ControlPanel getControlPanel() {
		return this.controlPanel;
	}

	public QueuePanel getQueuePanel() {
		return this.queuePanel;
	}

	/**
	 * Updates the percentage in the title
	 * 
	 * @param progressAsPercentage
	 */
	public void updateTitlePercentage(double progressAsPercentage) {
		this.setTitle("jNZB - " + percentFormat.format(progressAsPercentage)
				+ "%");
	}

	public void resetTitle() {
		this.setTitle("jNZB " + JNZB.VERSION + " - idle");
	}
}
